今天我們要接續昨天的份,來研究如何用kotlin寫出Product type以及Sum type
data class Customer(
val name: String,
val email: String,
val age: Int,
)
我們想要創造出一個顧客的Class,他有三個屬性,Name,email,age,但現在這樣的type,並不安全,我們也許會把email填到name裡面,也不會噴錯。因此我們可以再設計一下。
@JvmInline
value class Name(val value: String)
@JvmInline
value class Email(val value: String)
@JvmInline
value class Age(val value: Int)
data class Customer(
val name: Name,
val email: Email,
val age: Age,
)
這邊我們使用value class來包裝已經存在的primitive type,而且value class的特性,不會造成額外的開銷,因為它在運行時會被消除。
這樣做的話,我們再創造customer type時,就不會發生放錯屬性的時候了!
val customer: Customer = Customer(Name("JW"), Email("myEmail"), Age(25))
我們在設計時,可能email並不是一定要輸入的選項,那麼我們目前的Customer type可能就不能代表這件事情了,我們的domain type是可以表達事情的。因此我們可以這樣來改進,加上?
data class Customer(
val name: Name,
val email: Email?,
val age: Age,
)
假設我們的Customer要更進一步,新增電話號碼選項,並且phone跟email要擇一填寫,我們該怎麼做呢?難道要兩個都要可以給Null嗎?
data class Customer(
val name: Name,
val email: Email?,
val age: Age,
val phone: Phone?,
)
這樣好像可以表達,如果email為空,phone填值就可以了,如果phone為空,email填值就可以了。
但這樣會有幾個缺點。
可以將Sealed Class當作Enum的進階版本,我們就可以這樣來改寫
sealed interface ContactInfo
@JvmInline
value class Email(val value: String) : ContactInfo
@JvmInline
value class Phone(val value: String) : ContactInfo
這樣我們就可以使用ContactInfo來表示可能是email或是phone的二擇一囉
package model
@JvmInline
value class Name(val value: String)
sealed interface ContactInfo
@JvmInline
value class Email(val value: String) : ContactInfo
@JvmInline
value class Phone(val value: String) : ContactInfo
@JvmInline
value class Age(val value: Int)
data class Customer(
val name: Name,
val contactInfo: ContactInfo,
val age: Age,
)
val customer: Customer = Customer(Name("JW"), Phone("123"), Age(25))
val customer2: Customer = Customer(Name("JW"), Email("myEmail"), Age(25))
https://arrow-kt.io/learn/design/domain-modeling/